import * as THREE from "three"
import { MoveToFloorCommand, MoveToFloorIndexCommand } from "../command/floor.command"
import { FlyInCommand } from "../command/showcase.command"
import configConst from "../constant/config.const"
import SettingsData from "../data/SettingsData"
import SweepData from "../data/SweepData"
import optionsKeyEnum from "../enum/optionsKey.enum"
import sweepAlignmentEnum from "../enum/sweepAlignment.enum"
import transitionTypeEnum from "../enum/transitionType.enum"
import viewmodeEnum from "../enum/viewmode.enum"
import y from "../math/19674"
import { LoadIndicatorSuppressMessage } from "../message/tool.message"
import SymbolList from "../SymbolList"
import funcUtil from "../utils/func.util"
import OpenDeferred from "../utils/OpenDeferred"
import { isPanOrMesh } from "../utils/viewmode.util"
import CameraModule from "./CameraModule"
import CameraStartModule from "./CameraStartModule"
import LoadingGuiModule from "./LoadingGuiModule"
import Module from "./Module"
import ShowcaseSettingsModule from "./ShowcaseSettingsModule"
import SweepDataModule from "./SweepDataModule"
import ViewmodeModule from "./ViewmodeModule"

export default class ShowcaseStart extends Module {
  firstRenderPromise: OpenDeferred<any>
  flyInPromise: OpenDeferred<any>
  handleFlyIn: any
  renderer: any
  sweepData: any
  sweepModule: any
  cameraModule: any
  constructor() {
    super(...arguments),
      (this.name = "showcase-start"),
      (this.firstRenderPromise = new OpenDeferred()),
      (this.flyInPromise = new OpenDeferred()),
      (this.handleFlyIn = (e, t, i) => (this.renderer.startRender(!1), this.doStandardStart(e, t, i, !0).catch(() => this.renderer.startRender(!0))))
  }
  async init(e, t) {
    const [i, n] = await Promise.all([t.market.waitForData(SettingsData), t.getModule(CameraStartModule)])
    ;[this.sweepData, this.sweepModule, this.cameraModule, this.renderer] = await Promise.all([
      t.market.waitForData(SweepData),
      t.getModule(SweepDataModule),
      t.getModule(CameraModule),
      t.getModuleBySymbol(SymbolList.WEBGL_RENDERER)
    ])
    const s = i.tryGetProperty("quickstart", !1)
    s || (await t.getModule(ShowcaseSettingsModule))
    const a = n.getStartingPose()
    return (
      (s ? this.doQuickStart(a, t) : this.doStandardStart(a, t, i, !1)).then(() => this.flyInPromise.resolve()),
      this.bindings.push(
        t.commandBinder.addBinding(FlyInCommand, async e => {
          this.handleFlyIn(e.pose || n.getStartingPose(), t, i)
        })
      ),
      this.waitForFirstRender
    )
  }
  get waitForFirstRender() {
    return this.firstRenderPromise.nativePromise()
  }
  get waitForFlyin() {
    return this.flyInPromise.nativePromise()
  }
  async doQuickStart(e, t) {
    const i = this.sweepData.getStartSweep(e),
      n = i && i.id,
      s = await t.getModule(ViewmodeModule)
    return (
      await s.switchToMode(e.mode, transitionTypeEnum.Instant, {
        sweepID: n,
        position: e.camera.position || (i && i.position),
        rotation: e.camera.rotation,
        zoom: -1 !== e.camera.zoom ? e.camera.zoom : void 0
      }),
      t.broadcast(new LoadIndicatorSuppressMessage(!1)),
      (e.mode !== viewmodeEnum.Dollhouse && e.mode !== viewmodeEnum.Floorplan) ||
        (e.floorVisibility && (await t.commandBinder.issueCommandWhenBound(new MoveToFloorIndexCommand(e.floorVisibility.lastIndexOf(1), !0, 0)))),
      this.renderBeforeStarting(t)
    )
  }
  async doStandardStart(e, t, i, s) {
    var o
    const [h] = await Promise.all([t.getModule(ViewmodeModule)]),
      u = i.checkUrlParam("dh", 0, 1) || !i.tryGetProperty(optionsKeyEnum.Dollhouse, !0),
      p = i.checkUrlParam("fp", 0, 1) || !i.tryGetProperty(optionsKeyEnum.FloorPlan, !0)
    e && ((e.mode === viewmodeEnum.Dollhouse && u) || (e.mode === viewmodeEnum.Floorplan && p) || (e.mode === viewmodeEnum.Panorama && !e.pano)) && (e = null)
    const m = !e || (e && (e.mode === viewmodeEnum.Dollhouse || e.mode === viewmodeEnum.Floorplan)),
      g = !e || (e && !this.is360Pano(e) && isPanOrMesh(e.mode) && !u),
      f = e ? e.mode : viewmodeEnum.Panorama,
      b = this.sweepData.getStartSweep(e),
      S = b && b.id,
      T = this.sweepData.getFirstSweep()
    let M = T && T.rotation
    if (
      ((null === (o = null == e ? void 0 : e.camera) || void 0 === o ? void 0 : o.rotation) &&
        !funcUtil.isNullOBJ(e.camera.rotation) &&
        (M = e.camera.rotation),
      M && f !== viewmodeEnum.Floorplan && (M = y.Z(M)),
      g)
    ) {
      await t.getModuleBySymbol(SymbolList.MODEL_MESH)
      const i = h.getFlyinEndPose({
          sweepID: S,
          position: e ? e.camera.position : void 0,
          rotation: M
        }),
        o = h.getFlyinStartPose(i, s ? new THREE.Vector3(0, 0, 0) : void 0)
      t.broadcast(new LoadIndicatorSuppressMessage(!0))
      const u = S ? this.sweepModule.activateSweep({ sweepId: S }) : Promise.resolve()
      return (
        await h.switchToMode(viewmodeEnum.Dollhouse, transitionTypeEnum.Instant, o),
        await this.renderBeforeStarting(t),
        await funcUtil.waitRun(750),
        await this.cameraModule.moveTo({ transitionType: transitionTypeEnum.Interpolate, pose: i }).nativePromise(),
        await u,
        t.broadcast(new LoadIndicatorSuppressMessage(!1)),
        h.switchToMode(f, transitionTypeEnum.Interpolate, { sweepID: S, rotation: M }, configConst.DEFAULT_TRANSITION_TIME)
      )
    }
    await h.switchToMode(f, transitionTypeEnum.Instant, {
      sweepID: S,
      position: e ? e.camera.position : void 0,
      rotation: M,
      zoom: e && -1 !== e.camera.zoom ? e.camera.zoom : void 0
    }),
      m &&
        e &&
        (e.floorVisibility
          ? await t.commandBinder.issueCommandWhenBound(new MoveToFloorIndexCommand(e.floorVisibility.lastIndexOf(1), !0, 0))
          : await t.commandBinder.issueCommandWhenBound(new MoveToFloorCommand(null))),
      await this.renderBeforeStarting(t)
  }
  is360Pano(e) {
    if (e.pano.uuid) {
      const t = this.sweepData.getSweep(e.pano.uuid)
      if (t) return t.alignmentType !== sweepAlignmentEnum.ALIGNED
    } else {
      const e = this.sweepData.getFirstSweep()
      if (void 0 !== e) return e.alignmentType !== sweepAlignmentEnum.ALIGNED
    }
    return !1
  }
  async renderBeforeStarting(e) {
    await this.renderer.renderOnce(), await e.getModule(LoadingGuiModule), this.renderer.startRender(!0), this.firstRenderPromise.resolve()
  }
}
